﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace makitAxeman
{
    class AuditInfoHolder
    {
        private SortedList<string, IPAccessInfo> _IPInfo;

        private struct IPAccessInfo
        {
            internal int numberOfAttempts;
            internal List<DateTime> attemptAccessTimes;
            internal List<string> usernamesTriedToAccess;
            internal List<string> portsTriedToAccessFrom;
        }

        public AuditInfoHolder()
        {
            _IPInfo = new SortedList<string, IPAccessInfo>();
        }

        public void AddIPAccessInfo(string IP, string sourcePort, string username, DateTime accessAttemptTime)
        {
            IPAccessInfo ipInfo;

            if (_IPInfo.ContainsKey(IP))
            {
                ipInfo = _IPInfo[IP];
                ipInfo.numberOfAttempts += 1;
            }
            else
            {
                ipInfo = new IPAccessInfo();
                ipInfo.numberOfAttempts = 1;
                ipInfo.attemptAccessTimes = new List<DateTime>();
                ipInfo.usernamesTriedToAccess = new List<string>();
                ipInfo.portsTriedToAccessFrom = new List<string>();
            }

            var accessTimes = ipInfo.attemptAccessTimes;
            accessTimes.Add(accessAttemptTime);
            ipInfo.attemptAccessTimes = accessTimes;

            if (!ipInfo.usernamesTriedToAccess.Contains(username))
            {
                var usernamesTriedToAccess = ipInfo.usernamesTriedToAccess;
                usernamesTriedToAccess.Add(username);
                ipInfo.usernamesTriedToAccess = usernamesTriedToAccess;
            }

            if (sourcePort != null && !ipInfo.portsTriedToAccessFrom.Contains(sourcePort))
            {
                var portsTriedToAccessFrom = ipInfo.portsTriedToAccessFrom;
                portsTriedToAccessFrom.Add(sourcePort);
                ipInfo.portsTriedToAccessFrom = portsTriedToAccessFrom;
            }

            _IPInfo[IP] = ipInfo;
        }

        public TreeNode AddTreeData(TreeNode nodeToAddTo)
        {
            foreach (string currentIP in _IPInfo.Keys)
            {
                IPAccessInfo currentInfo = _IPInfo[currentIP];

                TreeNode currentIPNode = new TreeNode(String.Format("{0} [{1}]", currentIP, currentInfo.numberOfAttempts));


                // Add the usernames used
                var usernamesNode = new TreeNode(String.Format("Usernames Used [{0}]", currentInfo.usernamesTriedToAccess.Count.ToString()));

                foreach (var currentUsername in currentInfo.usernamesTriedToAccess)
                {
                    usernamesNode.Nodes.Add(currentUsername);
                }

                currentIPNode.Nodes.Add(usernamesNode);


                // Add the access attempt times
                var accessAttemptsNode = new TreeNode("Access Attempt Times");

                foreach (var currentAccessTime in currentInfo.attemptAccessTimes)
                {
                    accessAttemptsNode.Nodes.Add(currentAccessTime.ToString());
                }

                currentIPNode.Nodes.Add(accessAttemptsNode);


                // Add the ports
                var portsNode = new TreeNode("Source Ports");

                foreach (var sourcePort in currentInfo.portsTriedToAccessFrom)
                {
                    portsNode.Nodes.Add(sourcePort.ToString());
                }

                currentIPNode.Nodes.Add(portsNode);


                nodeToAddTo.Nodes.Add(currentIPNode);
            }

            return nodeToAddTo;
        }

        public string GetAbuseData()
        {
            StringBuilder abuseData = new StringBuilder();

            foreach (string currentIP in _IPInfo.Keys)
            {
                IPAccessInfo currentInfo = _IPInfo[currentIP];

                abuseData.AppendLine("=".PadRight(40,'='));

                abuseData.AppendLine("IP: " + currentIP);
                abuseData.AppendLine();

                abuseData.AppendLine("Attempt Times (UTC):");
                foreach (var currentAccessTime in currentInfo.attemptAccessTimes)
                {
                    abuseData.AppendLine(currentAccessTime.ToUniversalTime().ToString("F"));
                }

                abuseData.AppendLine();
                abuseData.AppendLine();

                abuseData.AppendLine("Source Ports Used:");
                foreach (var currentSourcePort in currentInfo.portsTriedToAccessFrom)
                {
                    abuseData.AppendLine(currentSourcePort);
                }

                abuseData.AppendLine();
                abuseData.AppendLine();

                abuseData.AppendLine("Usernames Attempted:");
                foreach (var currentUsername in currentInfo.usernamesTriedToAccess)
                {
                    abuseData.AppendLine(currentUsername);
                }

                abuseData.AppendLine("=".PadRight(40, '='));
                abuseData.AppendLine();
                abuseData.AppendLine();
                abuseData.AppendLine();
            }

            return abuseData.ToString();
        }
    }
}
